package com.xdtech.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class FileUtil
{
    private static final Logger logger = Logger.getLogger(FileUtil.class);
    // 默认utf-8编码
    public static final String defaultEnCode = "utf-8";

    public static boolean createDir(String destDirName)
    {
        File dir = new File(destDirName);
        if (dir.exists())
        {
            logger.info("创建目录" + destDirName + "失败，目标目录已存在！");
            return false;
        }
        if (!destDirName.endsWith(File.separator))
        {
            destDirName = destDirName + File.separator;
        }
        // 创建单个目录
        if (dir.mkdirs())
        {
            logger.info("创建目录" + destDirName + "成功！");
            return true;
        }
        else
        {
            logger.info("创建目录" + destDirName + "成功！");
            return false;
        }
    }

    public static boolean CreateFile(String destFileName)
    {
        File file = new File(destFileName);
        if (file.exists())
        {
            logger.info("创建单个文件" + destFileName + "失败，目标文件已存在！");
            return false;
        }
        if (destFileName.endsWith(File.separator))
        {
            logger.info("创建单个文件" + destFileName + "失败，目标不能是目录！");
            return false;
        }
        if (!file.getParentFile().exists())
        {
            if (!file.getParentFile().mkdirs())
            {
                return false;
            }
        }
        // 创建目标文件
        try
        {
            if (file.createNewFile())
            {
                logger.info("创建单个文件" + destFileName + "成功！");
                return true;
            }
            else
            {
                logger.info("创建单个文件" + destFileName + "失败！");
                return false;
            }
        }
        catch (IOException e)
        {
            logger.error("exception：", e);
            logger.info("创建单个文件" + destFileName + "失败！");
            return false;
        }
    }

    /**
     * 读取文本内容
     * 
     * @param textname
     *            文本名称
     * @return
     */
    public String readText(String textPath, String textName)
    {
        File file = new File(textPath + File.separator + textName);
        try
        {

            InputStream inputData = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int iReadLength = 0;
            StringBuffer bufferData = new StringBuffer();
            // 循环读取单个资源文件
            while ((iReadLength = inputData.read(buffer)) != -1)
            {
                bufferData.append(new String(buffer, 0, iReadLength, "utf-8"));// 转码
            }
            inputData.close();
            // String value=Test5.writeUnicode(bufferData.toString());
            return bufferData.toString();
        }
        catch (IOException e)
        {
            logger.error("exception：", e);
            return null;
        }
    }

    /**
     * 将内容写到文本中
     * 
     * @param textname
     *            　文本名称
     * @param date
     *            写入的内容
     * @return
     */
    public boolean writeText(String textPath, String textName, String data)
    {
        boolean flag = false;
        File filePath = new File(textPath);
        if (!filePath.exists())
        {
            filePath.mkdirs();
        }
        else
        {
            filePath.delete();
            filePath.mkdirs();
        }
        try
        {
            FileWriter fw = new FileWriter(textPath + File.separator + textName);
            fw.write(data);
            flag = true;
            if (fw != null)
            {
                fw.close();
            }
        }
        catch (IOException e)
        {
            logger.error("exception：", e);
        }

        return flag;
    }

    /**
     * 以指定编码写入文件（解决FileWriter 只能以当前系统编码写入文件）
     * 
     * @see
     * @param textPath 文件路径
     * @param textName 文件名
     * @param data 文件内容
     * @param enCode 编码
     * @return
     */
    public static boolean writeText(String textPath, String textName, String data, String enCode)
    {
        boolean flag = false;
        File filePath = new File(textPath);
        if (!filePath.exists())
        {
            filePath.mkdirs();
        }
        else
        {
            filePath.delete();
            filePath.mkdirs();
        }
        try
        {
            OutputStreamWriter out =
                    new OutputStreamWriter(new FileOutputStream(textPath + File.separator + textName),
                            enCode == null ? defaultEnCode : enCode);
            out.write(data);
            out.flush();
            if (out != null)
            {
                out.close();
            }
            flag = true;
        }
        catch (IOException e)
        {
            logger.error("exception：", e);
            ;
        }

        return flag;
    }

    // 文件打包下载
    public static HttpServletResponse downLoadFiles(String tempPath, File[] files, HttpServletRequest request,
                                                    HttpServletResponse response) throws Exception
    {
        try
        {
            /**
             * 这个集合就是你想要打包的所有文件， 这里假设已经准备好了所要打包的文件
             */
            // List<File> files = new ArrayList<File>();

            /**
             * 创建一个临时压缩文件， 我们会把文件流全部注入到这个文件中 这里的文件你可以自定义是.rar还是.zip
             */

            File file = new File(tempPath);
            if (!file.exists())
            {
                file.createNewFile();
            }
            response.reset();
            // response.getWriter()
            // 创建文件输出流
            FileOutputStream fileOutputStr = new FileOutputStream(file);
            /**
             * 打包的方法我们会用到ZipOutputStream这样一个输出流, 所以这里我们把输出流转换一下
             */
            ZipOutputStream zipOut = new ZipOutputStream(fileOutputStr);
            /**
             * 这个方法接受的就是一个所要打包文件的集合， 还有一个ZipOutputStream
             */
            zipFiles(files, zipOut);
            zipOut.close();
            fileOutputStr.close();
            return downloadZip(file, response);
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
        }
        /**
         * 直到文件的打包已经成功了， 文件的打包过程被我封装在FileUtil.zipFile这个静态方法中，
         * 稍后会呈现出来，接下来的就是往客户端写数据了
         */
        // OutputStream out = response.getOutputStream();

        return response;
    }

    /**
     * 下载zip文件
     * 
     * @see
     * @param tempPath
     * @param files 文件列表
     * @param request
     * @param response
     * @param comment 注释中文会乱码 暂时没有解决
     * @return
     * @throws Exception
     */
    public static HttpServletResponse downLoadFiles(String tempPath, File[] files, HttpServletRequest request,
                                                    HttpServletResponse response, String comment) throws Exception
    {
        try
        {
            /**
             * 这个集合就是你想要打包的所有文件， 这里假设已经准备好了所要打包的文件
             */
            // List<File> files = new ArrayList<File>();

            /**
             * 创建一个临时压缩文件， 我们会把文件流全部注入到这个文件中 这里的文件你可以自定义是.rar还是.zip
             */

            File file = new File(tempPath);
            if (!file.exists())
            {
                file.createNewFile();
            }
            response.reset();
            // response.getWriter()
            // 创建文件输出流
            FileOutputStream fileOutputStr = new FileOutputStream(file);
            /**
             * 打包的方法我们会用到ZipOutputStream这样一个输出流, 所以这里我们把输出流转换一下
             */
            ZipOutputStream zipOut = new ZipOutputStream(fileOutputStr);
            zipOut.setComment(new String(comment.getBytes(), defaultEnCode));
            /**
             * 这个方法接受的就是一个所要打包文件的集合， 还有一个ZipOutputStream
             */
            zipFiles(files, zipOut);
            zipOut.close();
            fileOutputStr.close();
            return downloadZip(file, response);
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
        }
        /**
         * 直到文件的打包已经成功了， 文件的打包过程被我封装在FileUtil.zipFile这个静态方法中，
         * 稍后会呈现出来，接下来的就是往客户端写数据了
         */
        // OutputStream out = response.getOutputStream();

        return response;
    }

    /**
     * 把接受的全部文件打成压缩包
     * 
     * @param List
     *            <File>;
     * @param org
     *            .apache.tools.zip.ZipOutputStream
     */
    public static void zipFiles(File[] files, ZipOutputStream outputStream)
    {
        int size = files.length;
        for (int i = 0; i < size; i++)
        {
            zipFile(files[i], outputStream);
        }
    }

    public static HttpServletResponse downloadZip(File file, HttpServletResponse response)
    {
        try
        {
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();

            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        }
        catch (IOException ex)
        {
            logger.error("exception：", ex);
        }
        finally
        {
            try
            {
                // File f = new File(file.getPath());
                // f.delete();
            }
            catch (Exception e)
            {
                logger.error("exception：", e);
            }
        }
        return response;
    }

    /**
     * 根据输入的文件与输出流对文件进行打包
     * 
     * @param File
     * @param org
     *            .apache.tools.zip.ZipOutputStream
     */
    public static void zipFile(File inputFile, ZipOutputStream ouputStream)
    {
        try
        {
            if (inputFile.exists())
            {
                /**
                 * 如果是目录的话这里是不采取操作的， 至于目录的打包正在研究中
                 */
                if (inputFile.isFile())
                {
                    FileInputStream inputStream = new FileInputStream(inputFile);
                    BufferedInputStream bufferInput = new BufferedInputStream(inputStream, 512);
                    // org.apache.tools.zip.ZipEntry
                    ZipEntry entry = new ZipEntry(inputFile.getName());
                    ouputStream.putNextEntry(entry);
                    // 向压缩文件中输出数据
                    int index;
                    byte[] buffer = new byte[512];
                    while ((index = bufferInput.read(buffer)) != -1)
                    {
                        ouputStream.write(buffer, 0, index);
                    }
                    // 关闭创建的流对象
                    bufferInput.close();
                    inputStream.close();
                }
                else
                {
                    try
                    {
                        File[] files = inputFile.listFiles();
                        for (int i = 0; i < files.length; i++)
                        {
                            zipFile(files[i], ouputStream, inputFile.getName());
                        }
                    }
                    catch (Exception e)
                    {
                        logger.error("exception：", e);
                        ;
                    }
                }
            }
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
        }
    }

    /**
     * 根据输入的文件与输出流对文件并读取子文件夹中的文件打包
     * 
     * @author ZK
     * @see 相关类或方法，不需要请删除此行
     * @since 2015年4月10日 下午5:11:17
     * @param inputFile
     * @param ouputStream
     * @param path
     */
    public static void zipFile(File inputFile, ZipOutputStream ouputStream, String path)
    {
        try
        {
            if (inputFile.exists())
            {
                /**
                 * 如果是目录的话这里是不采取操作的， 至于目录的打包正在研究中
                 */
                if (inputFile.isFile())
                {
                    FileInputStream inputStream = new FileInputStream(inputFile);
                    BufferedInputStream bufferInput = new BufferedInputStream(inputStream, 512);
                    // org.apache.tools.zip.ZipEntry
                    ZipEntry entry = new ZipEntry(path + File.separator + inputFile.getName());
                    ouputStream.putNextEntry(entry);
                    // 向压缩文件中输出数据
                    int index;
                    byte[] buffer = new byte[512];
                    while ((index = bufferInput.read(buffer)) != -1)
                    {
                        ouputStream.write(buffer, 0, index);
                    }
                    // 关闭创建的流对象
                    bufferInput.close();
                    inputStream.close();
                }
                else
                {
                    try
                    {
                        File[] files = inputFile.listFiles();
                        for (int i = 0; i < files.length; i++)
                        {
                            zipFile(files[i], ouputStream, path + File.separator + inputFile.getName());
                        }
                    }
                    catch (Exception e)
                    {
                        logger.error("exception：", e);
                        ;
                    }
                }
            }
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
        }

    }

    // 删除单个文件
    public static boolean deleteFile(String fileName)
    {
        File file = new File(fileName);
        if (file.isFile() && file.exists())
        {
            file.delete();
            logger.info("删除单个文件" + fileName + "成功！");
            return true;
        }
        else
        {
            // logger.info("删除单个文件" + fileName + "失败！");
            return false;
        }
    }

    // 删除文件夹，已经文件目录下的文件和字目录下的文件
    public static boolean deleteDirectory(String dir)
    {
        // 如果dir不以文件分隔符结尾，自动添加文件分隔符
        if (!dir.endsWith(File.separator))
        {
            dir = dir + File.separator;
        }
        File dirFile = new File(dir);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory())
        {
            logger.info("删除目录失败" + dir + "目录不存在！");
            return false;
        }
        boolean flag = true;
        // 删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++)
        {
            // 删除子文件
            if (files[i].isFile())
            {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag)
                {
                    break;
                }
            }
            // 删除子目录
            else
            {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag)
                {
                    break;
                }
            }
        }

        if (!flag)
        {
            logger.info("删除目录失败");
            return false;
        }
        // 删除当前目录
        if (dirFile.delete())
        {
            logger.info("删除目录" + dir + "成功！");
            return true;
        }
        else
        {
            logger.info("删除目录" + dir + "失败！");
            return false;
        }
    }

    /**
     * 根据url下载文件到本地
     * 
     * @param url
     * @param request 如果有传request参数，直接获取tomcat部署路径，如果没有，则手机获取
     * @return
     */
    public static String downloadFile(String sURL, HttpServletRequest request)
    {
        int nStartPos = 0;
        int nRead = 0;
        int index = sURL.lastIndexOf("/");
        String sName = UUID.randomUUID().toString() + sURL.substring(index + 1);// 保证文件名称唯一
        String sPath = "";
        String filePath = "";
        try
        {
            if (request != null)
            {
                sPath = request.getRealPath("/") + "fireware" + File.separator + "temp";
            }
            else
            {
                String tempPath = System.getProperty("user.dir");
                if (tempPath.length() > 3)
                {
                    tempPath = tempPath.substring(0, tempPath.length() - 3);
                    sPath =
                            tempPath + "webapps" + File.separator + "ROOT" + File.separator + "fireware"
                                    + File.separator + "temp";
                }
                else
                {
                    return "";
                }
            }
            filePath = sPath + File.separator + sName;

            FileUtil.CreateFile(filePath);
            URL url = new URL(sURL);
            HttpURLConnection httpConnection = null;
            InputStream input = null;
            RandomAccessFile oSavedFile = null;
            try
            {
                httpConnection = (HttpURLConnection) url.openConnection();
                long nEndPos = getFileSize(sURL);
                oSavedFile = new RandomAccessFile(filePath, "rw");
                httpConnection.setRequestProperty("User-Agent", "Internet Explorer");
                String sProperty = "bytes=" + nStartPos + "-";
                httpConnection.setRequestProperty("RANGE", sProperty);
                input = httpConnection.getInputStream();
                byte[] b = new byte[1024];
                while ((nRead = input.read(b, 0, 1024)) > 0 && nStartPos < nEndPos)
                {
                    oSavedFile.write(b, 0, nRead);
                    nStartPos += nRead;
                }
            }
            catch (Exception e)
            {
                logger.error("exception：", e);
                ;
            }
            finally
            {
                httpConnection.disconnect();
                input.close();
                oSavedFile.close();
            }
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
            return "";
        }
        logger.info("下载到本地的文件路径：" + filePath);
        return filePath;
    }

    /**
     * 获得文件长度
     * 
     * @param sURL
     * @return
     */
    public static long getFileSize(String sURL)
    {
        int nFileLength = -1;
        try
        {
            URL url = new URL(sURL);
            HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
            httpConnection.setRequestProperty("User-Agent", "Internet Explorer");

            int responseCode = httpConnection.getResponseCode();
            if (responseCode >= 400)
            {
                logger.error("Error Code : " + responseCode);
                return -2; // -2 represent access is error
            }
            String sHeader;
            for (int i = 1;; i++)
            {
                sHeader = httpConnection.getHeaderFieldKey(i);
                if (sHeader != null)
                {
                    if (sHeader.equals("Content-Length"))
                    {
                        nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
                        break;
                    }
                }
                else
                {
                    break;
                }
            }
            httpConnection.disconnect();
        }
        catch (IOException e)
        {
            logger.error("exception：", e);
            ;
        }
        catch (Exception e)
        {
            logger.error("exception：", e);
            ;
        }
        return nFileLength;
    }

    public static void delete(File file)
    {
        if (file != null && file.exists())
        {
            if (file.isFile())
            {
                file.delete();
            }
            else if (file.isDirectory())
            {
                File files[] = file.listFiles();
                for (int i = 0; i < files.length; i++)
                {
                    delete(files[i]);
                }
            }
            file.delete();
        }
    }

}
